package com.why.rpc.core.client.channel;


import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import com.why.rpc.core.common.message.RpcRequest;
import com.why.simpleboot.core.core.aop.proxy.NoProxyMethodName;

import java.lang.reflect.Method;

/**
 * @program: why-rpc-framework
 * @description:
 * @author: @why
 * @create: 2021-03-15 17:19
 **/
@Slf4j
public class ProxyClient implements MethodInterceptor {

    public ProxyClient() {

    }

    /**
     * 生成代理类
     *
     * @param service
     * @return
     */
    public static Object getProxy(Class<?> service) {
        Enhancer enhancer = new Enhancer();
        ProxyClient callBack = new ProxyClient();
        enhancer.setClassLoader(service.getClassLoader());
        enhancer.setCallback(callBack);
        enhancer.setSuperclass(service);
        return enhancer.create();
    }

    /**
     * @param o           代理类对象
     * @param method      被代理类的方法
     * @param objects     被代理类方法的参数
     * @param methodProxy 调用被代理类对象的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (!NoProxyMethodName.NO_PROXY_METHODS.contains(method.getName())) {
            //先封装好请求
            RpcRequest request = RpcRequest.builder()
                    .methodName(method.getName())
                    .interfaceName(method.getDeclaringClass().getCanonicalName())
                    .methodParameters(objects)
                    .parameterTypes(method.getParameterTypes()).build();

            log.info("请求创建完成{}", request);
            //接着在代理类中发送请求即可.
            Object object = NettyRpcClient.getClientInstance().sendRequest(request);
            log.info("调用请求成功!!!调用后得到的请求信息为{}", object);
            return object;

        }
        return methodProxy.invokeSuper(o, objects);
//        使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升
        //使用  methodProxy.invokeSuper方法 应该使用 生成的代理对象，也就是o对象
        //使用methodProxy.invoke方法，应该使用要被代理的对象

    }
}
